﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using Microsoft.Office.Interop.Excel;
using System.ComponentModel;

namespace GE_Database_Manager
{
	public abstract class Database
	{
      
        /// <summary>
        /// Delegate to pass the progress information accross each class
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void PassProgress(object sender, ProgressChangedEventArgs e);
        public PassProgress passProgress;

       
		/// <summary>
		/// Main database processing function
		/// </summary>
		/// <returns>True if processing completed successfully; false otherwise</returns>
		public abstract bool Process(Standardized_Wrapper wrapper);

        /// <summary>
        ///  Getter and setter for key
        ///  all databases should include a key
        /// </summary>
        public abstract string Key { get; set; }

        /// <summary>
        /// Progress step 
        /// </summary>
        public abstract int ProgressStep { get; set; }

		/// <summary>
		/// ProcessPDF: takes a file path path to a .pdf, extracts the text from the pdf using iText.
        /// The Sieral Number and location are extracted from the text and returned as strings in a tuple
		/// </summary>
		/// <returns>
        /// ProcessPDF: returns a tuple of strings (SieralNumber, Location)
        /// </returns>
        protected Tuple<string, string> ProcessPDF(string pdfPath)
		{
            // if the pdf path does not exist return null 
            if (!File.Exists(pdfPath) || Path.GetExtension(pdfPath) != ".pdf")
                return new Tuple<string, string>(null, null);

            // extract text from pdf using iText
            StringBuilder text = new StringBuilder();
            PdfReader pr = new PdfReader(pdfPath);
            for (int page = 1; page <= pr.NumberOfPages; page++)
            {
                ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
                string currentText = PdfTextExtractor.GetTextFromPage(pr, page, strategy);
                currentText = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText)));
                text.Append(currentText);
            }
            pr.Close();

            // get Serial Number out of text extracted from pdf
            string sn;
            Match match = Regex.Match(text.ToString(), @"\s*GE S/N:\s*(\w+)\s*", RegexOptions.IgnoreCase);
            if (match.Success)
                sn = match.Groups[1].Value;
            else
                sn = null;

            // get Location out of text extracted from pdf
            string loc;
            match = Regex.Match(text.ToString(), @"\s+(\w+\s\w+)\s+ DM Number:", RegexOptions.IgnoreCase);
            if (match.Success)
                loc = match.Groups[1].Value;
            else
                loc = null;

            // return Serial Number and Location
            return new Tuple<string, string>(sn, loc);
		}

		/// <summary>
        /// ProcessMalfunctionTags: takes a file path, to a .txt file and 
        /// extracts all information from malfunction tag text document
		/// </summary>
		/// <returns>
        /// ProcessMalfunctionTags: returns a String object containing the malfunction information
        /// or null if the file path does not exist
        /// </returns>
		protected String ProcessMalfunctionTags(string txtPath)
		{
            // if the file path does not exist return null
            if (!File.Exists(txtPath) || !txtPath.ToLower().Contains("malfunctiontag") || Path.GetExtension(txtPath) != ".txt")
                return null;

            // get the data, replace newlines with a space, remove leading / trailing white space, and add an endline to the end
            String data = File.ReadAllText(txtPath).Replace(System.Environment.NewLine, " ").Trim();

            // if nothing is in the file return none
            if (String.IsNullOrEmpty(data))
                return "None";

            // else return
            return data;
		}

        /// <summary>
        /// ProcessComments: takes a file path, to a .txt file and 
        /// extracts all information from comments text document
        /// </summary>
        /// <returns>
        /// ProcessComments: returns a String object containing the comments information
        /// or null if the file path does not exist
        /// </returns>
        protected String ProcessComments(string txtPath)
        {
            // if the file path does not exist return null
            if (!File.Exists(txtPath) || !txtPath.ToLower().Contains("comments") || Path.GetExtension(txtPath) != ".txt")
                return null;

            // get the data, replace newlines with a space, remove leading / trailing white space, and add an endline to the end
            String data = File.ReadAllText(txtPath).Replace(System.Environment.NewLine, " ").Trim();

            // if nothing is in the file return none
            if (String.IsNullOrEmpty(data))
                return "None";

            // else return
            return data;
        }

		/// <summary>
		/// ProcessesExcel: takes a file path to a .pdf file and
        /// extracts the values from the pertinent cells,
        /// adding them to a dictionary whos key values are the 
        /// same as the entity attribute names. Stages one and two
        /// needed their names perceded by s2 and s1, as they share 
        /// the same attribute names. 
		/// </summary>
		/// <returns>
        /// ProcessesExcel: returns a dictionary where
        /// (key = attributeName, value = attributeValue)
        /// </returns>
		protected Dictionary<string, string> ProcessExcel(string xlsPath)
		{
            // if the file path does not exist return an empty dict
            if (!File.Exists(xlsPath))
                return new Dictionary<string, string>();

            // open the excel workbook and make the first worksheet active
            Application excel = new Application();
            excel.DisplayAlerts = false;
            Workbook wb = excel.Workbooks.Open(xlsPath);
            Worksheet ws = wb.ActiveSheet;

            // create dict
            Dictionary<string, string> xlsDict = new Dictionary<string, string>();

            // add gearbox kinematic data
            xlsDict.Add("gearbox_make", ws.Cells[3, "B"].Value.ToString());
            
            // add stage 1 data
            xlsDict.Add("s1 type", ws.Cells[16, "B"].Value.ToString());
            xlsDict.Add("s1 sun_tooth_count", ws.Cells[18, "B"].Value.ToString());
            xlsDict.Add("s1 fixed", ws.Cells[19, "B"].Value.ToString());
            xlsDict.Add("s1 ring_tooth_count", ws.Cells[20, "B"].Value.ToString());
            xlsDict.Add("s1 planet_count", ws.Cells[21, "B"].Value.ToString());
            xlsDict.Add("s1 planet_tooth_count", ws.Cells[23, "B"].Value.ToString());

            // add stage 2 data
            xlsDict.Add("s2 type", ws.Cells[46, "B"].Value.ToString());
            xlsDict.Add("s2 gear_tooth_count", ws.Cells[66, "B"].Value.ToString());
            xlsDict.Add("s2 pinion_tooth_count", ws.Cells[67, "B"].Value.ToString());

            // add stage 3 data
            xlsDict.Add("s3 type", ws.Cells[76, "B"].Value.ToString());
            xlsDict.Add("s3 gear_tooth_count", ws.Cells[96, "B"].Value.ToString());
            xlsDict.Add("s3 pinion_tooth_count", ws.Cells[97, "B"].Value.ToString());

            // close the excel workbook
            wb.Save();
            wb.Close();
            excel.DisplayAlerts = true;
            excel.Quit();

            // return dict
			return xlsDict;
		}
	}
}
